package com.fy.fyspace.service.hotness.strategy.impl;

import com.fy.fyspace.model.dto.hotness.HotnessCalculationDTO;
import com.fy.fyspace.service.hotness.strategy.HotnessCalculationStrategy;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Date;

/**
 * 标准热度计算策略实现
 * 设计模式：策略模式的具体实现
 * 作用：实现标准的热度计算算法，包含时间衰减因子
 * 
 * @author fwq
 * @since 2024-12-19
 */
@Slf4j
@Component("standardHotnessStrategy")
public class StandardHotnessStrategy implements HotnessCalculationStrategy {
    
    // 默认权重配置
    private static final BigDecimal DEFAULT_DOWNLOAD_WEIGHT = new BigDecimal("3.0");
    private static final BigDecimal DEFAULT_LIKE_WEIGHT = new BigDecimal("2.0");
    private static final BigDecimal DEFAULT_FAVORITE_WEIGHT = new BigDecimal("4.0");
    
    // 时间衰减因子配置（每天衰减0.95）
    private static final BigDecimal TIME_DECAY_FACTOR = new BigDecimal("0.95");
    
    @Override
    public BigDecimal calculateHotness(HotnessCalculationDTO calculationDTO) {
        try {
            log.debug("开始计算热度，图片ID: {}", calculationDTO.getPictureId());
            
            // 验证输入参数
            if (calculationDTO == null) {
                log.error("计算DTO为空");
                return BigDecimal.ZERO;
            }
            
            if (calculationDTO.getPictureId() == null) {
                log.error("图片ID为空");
                return BigDecimal.ZERO;
            }
            
            // 获取权重，如果为空则使用默认值
            BigDecimal downloadWeight = calculationDTO.getDownloadWeight() != null ? 
                calculationDTO.getDownloadWeight() : DEFAULT_DOWNLOAD_WEIGHT;
            BigDecimal likeWeight = calculationDTO.getLikeWeight() != null ? 
                calculationDTO.getLikeWeight() : DEFAULT_LIKE_WEIGHT;
            BigDecimal favoriteWeight = calculationDTO.getFavoriteWeight() != null ? 
                calculationDTO.getFavoriteWeight() : DEFAULT_FAVORITE_WEIGHT;
            
            log.debug("权重配置 - 下载: {}, 点赞: {}, 收藏: {}", downloadWeight, likeWeight, favoriteWeight);
            
            // 获取计数值，如果为空则使用0
            int downloadCount = calculationDTO.getDownloadCount() != null ? calculationDTO.getDownloadCount() : 0;
            int likeCount = calculationDTO.getLikeCount() != null ? calculationDTO.getLikeCount() : 0;
            int favoriteCount = calculationDTO.getFavoriteCount() != null ? calculationDTO.getFavoriteCount() : 0;
            
            log.debug("计数值 - 下载: {}, 点赞: {}, 收藏: {}", downloadCount, likeCount, favoriteCount);
            
            // 计算各项得分
            BigDecimal downloadScore = downloadWeight.multiply(new BigDecimal(downloadCount));
            BigDecimal likeScore = likeWeight.multiply(new BigDecimal(likeCount));
            BigDecimal favoriteScore = favoriteWeight.multiply(new BigDecimal(favoriteCount));
            
            log.debug("各项得分 - 下载: {}, 点赞: {}, 收藏: {}", downloadScore, likeScore, favoriteScore);
            
            // 计算基础分数
            BigDecimal baseScore = downloadScore.add(likeScore).add(favoriteScore);
            
            log.debug("基础分数: {}", baseScore);
            
            // 计算时间衰减因子
            BigDecimal timeDecayFactor = calculateTimeDecayFactor(calculationDTO.getCreateTime(), calculationDTO.getCalculateTime());
            
            log.debug("时间衰减因子: {}", timeDecayFactor);
            
            // 应用时间衰减
            BigDecimal finalScore = baseScore.multiply(timeDecayFactor);
            
            // 保留两位小数
            BigDecimal result = finalScore.setScale(2, RoundingMode.HALF_UP);
            
            log.debug("最终热度分数: {}", result);
            
            return result;
            
        } catch (Exception e) {
            log.error("计算热度分数时发生错误，图片ID: {}, 错误详情: {}", 
                calculationDTO != null ? calculationDTO.getPictureId() : "null", e.getMessage(), e);
            return BigDecimal.ZERO;
        }
    }
    
    /**
     * 计算时间衰减因子
     * 公式：衰减因子 = 0.95 ^ (天数)
     * 
     * @param createTime 创建时间
     * @param calculateTime 计算时间
     * @return 时间衰减因子
     */
    private BigDecimal calculateTimeDecayFactor(Date createTime, Date calculateTime) {
        if (createTime == null || calculateTime == null) {
            return BigDecimal.ONE;
        }
        
        // 计算天数差
        long timeDiff = calculateTime.getTime() - createTime.getTime();
        long daysDiff = timeDiff / (24 * 60 * 60 * 1000);
        
        if (daysDiff <= 0) {
            return BigDecimal.ONE;
        }
        
        // 计算衰减因子：0.95 ^ daysDiff
        BigDecimal decayFactor = TIME_DECAY_FACTOR.pow((int) daysDiff);
        
        // 最小衰减因子为0.1
        return decayFactor.max(new BigDecimal("0.1"));
    }
    
    @Override
    public String getStrategyName() {
        return "StandardHotnessStrategy";
    }
    
    @Override
    public String getStrategyDescription() {
        return "标准热度计算策略：基于下载、点赞、收藏的加权计算，包含时间衰减因子";
    }
    
    @Override
    public String getStrategyType() {
        return "STANDARD";
    }
    
    @Override
    public boolean isEnabled() {
        return true;
    }
} 